﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MatrixLibrary
{
    public class Matrix
    {
        private int _nrow;
        private int _ncol;
        private int[,] matrix;
        
        public Matrix(int rows, int cols) 
        {
            this._nrow = rows;
            this._ncol = cols;

            matrix = new int[this._nrow, this._ncol];
        }        

        public int this[int row, int col] 
        {
            get
            {
                return matrix[row, col];
            }
            set
            {
                matrix[row, col] = value;
            }
        }

        public override string ToString()
        {
            string datos = string.Empty;

            string _fmt = "{0,5}";
            for (int i = 0; i < this._nrow; i++)
            {
                for (int j = 0; j < this._ncol; j++)
                    datos += string.Format(_fmt, matrix[i, j]);
                
                datos += System.Environment.NewLine;
            }
            return datos;
        }


        #region METODOS AUXILIARES PARA EL TRATAMIENTO DE MATRICES

        
        /// <summary>
        /// Intercambia la fila ORIGEN por la fila DESTINO.
        /// Las filas se cuentan desde cero a n-1
        /// </summary>
        /// <param name="fOrigen"></param>
        /// <param name="fDestino"></param>
        public void IntercabiarFila(int fOrigen, int fDestino) 
        {
            //PASOS PARA INTERCAMBIAR FILA
            //  1 - Copio valores de la fila destino en un auxiliar
            //  2 - Copio valores de origen en destino
            //  3 - Copio vector auxiliar en fila origen
                        
            if (fDestino < this._nrow) 
            {                                
                int aux = 0;                
                for (int j = 0; j < this._ncol; j++)
                {
                    aux = matrix[fDestino, j];
                    matrix[fDestino, j] = matrix[fOrigen, j];
                    matrix[fOrigen, j]  = aux;
                }
            }
        }

        public void MultiplicaEscalar(int fila, int k)
        {
            for (int j = 0; j < this._ncol; j++)
                matrix[fila, j] = k * matrix[fila, j];
        }

        /// <summary>
        /// A la fila Destino, le sumo la fila origen multiplicada por el 
        /// escalar k
        /// </summary>
        /// <param name="fDestino"></param>
        /// <param name="fOrigen"></param>
        /// <param name="k"></param>
        public void SumarFilaPorMultiploDeOtra(int fDestino, int fOrigen, int k) 
        {
            //int[] aux = new int[this._ncol];
            int aux = 0;

            for (int j = 0; j < this._ncol; j++)
            {
                aux = k * matrix[fOrigen, j];
                matrix[fDestino, j] = matrix[fDestino, j] + aux;
            }
        }

        /// <summary>
        /// Una fila es nula cuando todos sus elementos son nulos.
        /// nulo = cero
        /// </summary>
        /// <param name="nroFila"></param>
        /// <returns></returns>
        private bool EsFilaNula(int nroFila) 
        {
            bool esFilaNula = true;
            for (int j = 0; j < this._ncol; j++)
            {
                if (matrix[nroFila, j] != 0) 
                {
                    esFilaNula = false;
                    break;
                }
            }
            return esFilaNula;
        }

        #endregion


        #region PROPIEDADES DE LA MATRIZ

        public string Orden
        {
            get
            {
                return string.Format("{0}x{1}", this._nrow, this._ncol);
            }
        }

        public bool EsMismoOrden(Matrix m)
        {
            return this.Orden.Equals(m.Orden);
        }

        public bool EsCuadrada 
        {
            get {
                return ( this._nrow == this._ncol );
            }
        }

        public bool EsNula
        {
            get {
                return (this._nrow == 0 && this._ncol == 0);
            }
        }

        public bool EsMatrixIdentidad
        {
            get {
                bool esIdentidad = true;
                if (this.EsNula || !this.EsCuadrada)
                {
                    esIdentidad = false;
                }
                else
                {
                    for (int i = 0; i < matrix.GetLength(0); i++)
                    {
                        for (int j = 0; j < matrix.GetLength(1); j++)
                        {
                            if (esIdentidad)
                            {
                                if (i == j)
                                {
                                    if (matrix[i, j] != 1)
                                        esIdentidad = false;
                                }
                                else
                                {
                                    if (matrix[i, j] != 0)
                                        esIdentidad = false;
                                }
                            }
                        }
                    }
                }

                return esIdentidad;                
            }
        }

        #endregion


    }
}
